package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.commons.constants.CourseConstants;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CourseAuditDto;
import com.xuecheng.commons.model.dto.CourseBaseDto;
import com.xuecheng.commons.model.dto.CourseDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CourseBaseVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.AuthInfoThreadLocal;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.config.MinioProperties;
import com.xuecheng.content.domain.CourseBase;
import com.xuecheng.content.domain.CoursePub;
import com.xuecheng.content.domain.Teachplan;
import com.xuecheng.content.mappers.CourseBaseMapper;
import com.xuecheng.content.mappers.TeachplanMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.CoursePubService;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.web.exceptions.BusinessException;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author 七安
 * @since 2022-09-17
 */
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private MinioProperties minioProperties;

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    @Autowired
    private TeachplanService teachplanService;

    @Autowired
    private CoursePubService coursePubService;

    @Autowired
    private UploadHtml uploadHtml;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 课程封面上传
     *
     * @param uploadFile 封面文件
     * @return 上传后的地址
     */
    @Override
    public String fileUpload(MultipartFile uploadFile) throws IOException, ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //获取流
        InputStream inputStream = uploadFile.getInputStream();
        //设置上传后的文件名
        String fileName = "/images/" + new SimpleDateFormat("yyyy/MM/dd/").format(new Date()) + UUID.randomUUID().toString() + uploadFile.getOriginalFilename();
        //上传
        minioClient.putObject(PutObjectArgs.builder().object(fileName).bucket(minioProperties.getBucket()).stream(inputStream, inputStream.available(), -1).contentType("image/jpg").build());
        //设置访问路径 (域名+桶名+文件名)
        return minioProperties.getDomain() + minioProperties.getBucket() + fileName;
    }

    /**
     * 分页查询课程
     *
     * @param courseDto   接收部分查询条件，例如名字，状态
     * @param pageRequest 分页数据
     * @return 课程列表
     */
    @Override
    public PageResponseResult findClassList(CourseDto courseDto, PageRequest pageRequest) {
        //创建分页对象
        Page<CourseBase> courseBasePage = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
        //创建wrapper封装查询条件
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        //根据课程名字模糊匹配
        wrapper.like(StringUtils.isNotEmpty(courseDto.getCourseName()), CourseBase::getName, courseDto.getCourseName());
        //根据审核状态匹配
        wrapper.eq(StringUtils.isNotEmpty(courseDto.getAuditStatus()), CourseBase::getAuditStatus, courseDto.getAuditStatus());
        //根据课程类型匹配
        wrapper.eq(StringUtils.isNotEmpty(courseDto.getTeachmode()), CourseBase::getTeachmode, courseDto.getTeachmode());
        //查询
        courseBasePage = this.page(courseBasePage, wrapper);
        //获取总条数
        long total = courseBasePage.getTotal();
        //返回结果
        return new PageResponseResult(total, courseBasePage.getRecords());
    }

    /**
     * 添加课程
     *
     * @param courseBaseDto 课程信息
     * @return 添加完成后返沪的id
     */
    @Override
    public CourseBaseVo insertCourse(CourseBaseDto courseBaseDto) throws BusinessException {
        //转成实体domain
        CourseBase courseBase = BeanHelper.copyProperties(courseBaseDto, CourseBase.class);
        //设置机构ID
        courseBase.setCompanyId(AuthInfoThreadLocal.getCompanyId());
        //设置机构名称
        courseBase.setCompanyName(AuthInfoThreadLocal.getAuthInfo().getCompanyName());
        //设置审核状态(未提交)
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS);
        //设置创建时间
        courseBase.setCreateDate(new Date());
        //设置初始三级小节总数
        courseBase.setPlanNum(0);
        //添加课程
        boolean save = this.save(courseBase);
        if (!save) {
            //如果保存失败，抛出异常
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        //添加课程计划
        Teachplan teachplan = new Teachplan();
        //设置课程计划名称
        teachplan.setPname(courseBase.getName());
        //设置课程的分级
        teachplan.setGrade(CourseConstants.FIRST_LEVEL);
        //设置课程的父级id(0代表没有了)
        teachplan.setParentid(0L);
        //设置机构ID
        teachplan.setCompanyId(AuthInfoThreadLocal.getCompanyId());
        //设置关联的课程ID
        teachplan.setCourseId(courseBase.getId());
        //添加到课程计划表中
        teachplanService.save(teachplan);
        CourseBaseVo courseBaseVo = new CourseBaseVo();
        courseBaseVo.setCourseBaseId(courseBase.getId());
        return courseBaseVo;
    }

    /**
     * 根据ID删除
     *
     * @param courseId 要删除的id
     * @return 删除结果
     * @throws BusinessException 删除失败
     */
    @Override
    public void deleteCourseById(String courseId) throws BusinessException {
        //根据id判断
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CourseBase::getAuditStatus, CourseConstants.AUDIT_COMMIT_STATUS, CourseConstants.AUDIT_PASTED_STATUS, CourseConstants.AUDIT_PUBLISHED_STATUS);
        wrapper.eq(CourseBase::getId, courseId);
        CourseBase courseBase = this.getOne(wrapper);
        //顺便删除大纲的
        LambdaQueryWrapper<Teachplan> tpWrapper = new LambdaQueryWrapper<>();
        tpWrapper.eq(Teachplan::getCourseId, courseId);
        teachplanService.remove(tpWrapper);
        if (courseBase != null) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        courseBaseMapper.deleteById(courseId);
    }

    /**
     * 根据id修改课程
     *
     * @param courseBaseDto 要修改的内容
     * @return 课程id
     */
    @Override
    public Long updateCourseById(CourseBaseDto courseBaseDto) throws BusinessException {
        //转成实体对象
        CourseBase courseBase = BeanHelper.copyProperties(courseBaseDto, CourseBase.class);
        //判断当前课程是否能修改
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CourseBase::getAuditStatus, CourseConstants.AUDIT_COMMIT_STATUS, CourseConstants.AUDIT_PASTED_STATUS, CourseConstants.AUDIT_PUBLISHED_STATUS);
        wrapper.eq(CourseBase::getId, courseBase.getId());
        //查询
        CourseBase one = courseBaseMapper.selectOne(wrapper);
        //不等null证明当前传入的课程属于以上三种状态，不能更新
        if (one != null) {
            throw new BusinessException(ErrorCode.UPDATEEERROR);
        }
        //修改
        boolean b = this.updateById(courseBase);
        if (!b) {
            throw new BusinessException(ErrorCode.UPDATEEERROR);
        }
        return courseBase.getId();
    }

    /**
     * 提交审核
     *
     * @param courseBaseId 要提交的课程id
     * @return 结果
     */
    @Override
    public void commitVerify(Long courseBaseId) throws BusinessException {
        //判断当前课程是否能够提交
        CourseBase courseBase = courseBaseMapper.selectById(courseBaseId);
        if (courseBase == null && (courseBase.getAuditStatus().equals(CourseConstants.AUDIT_DISPAST_STATUS) || CourseConstants.AUDIT_UNPAST_STATUS.equals(courseBase.getAuditStatus()))) {
            throw new BusinessException(ErrorCode.ERROR);
        }
        courseBase.setAuditStatus(CourseConstants.AUDIT_COMMIT_STATUS);
        this.updateById(courseBase);
    }

    /**
     * 审核课程
     *
     * @param courseAuditDto 审核的意见和状态
     */
    @Override
    public void verifyCourse(CourseAuditDto courseAuditDto) throws BusinessException {
        //根据id查询
        CourseBase courseBase = courseBaseMapper.selectById(courseAuditDto.getCourseBaseId());
        //判断状态
        if (courseBase == null && !courseBase.getAuditStatus().equals(CourseConstants.AUDIT_COMMIT_STATUS)) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        //设置审核状态和意见
        courseBase.setAuditStatus(courseAuditDto.getAuditStatus());
        courseBase.setAuditMind(courseAuditDto.getAuditMind());
        //更新
        courseBaseMapper.updateById(courseBase);
    }

    /**
     * 课程下架
     *
     * @param courseId 课程id
     * @return 结果
     */
    @Override
    public ResponseResult courseSoldOut(Long courseId) throws BusinessException, ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //判空
        if (courseId == null) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        //根据id查询
        LambdaQueryWrapper<CoursePub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CoursePub::getCourseId, courseId);
        CoursePub coursePub = coursePubService.getOne(wrapper);
        //修改课程状态
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNLINE_STATUS);
        courseBaseMapper.updateById(courseBase);
        //删除minio中的静态文件
        try {
            uploadHtml.deleteHtml(coursePub.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        //删除数据库中对应的课程发布信息
        boolean b = coursePubService.remove(wrapper);
        if (!b) {
            throw new BusinessException(ErrorCode.PARAMSERROR);
        }
        //发送MQ消息
        rabbitTemplate.convertAndSend("content-exchange", "course-soldOut", coursePub.getId());
        return ResponseResult.okResult();
    }
}